/*-------------------------------------------------------------------------
 *
 * stringinfo.h
 *	  “StringInfo” 函数的声明/定义。
 *
 * StringInfo 提供一种可扩展的字符串数据类型（当前限制为 1GB）。
 * 可以用于缓冲普通 C 字符串（以 null 结尾的文本）或任意二进制数据。
 * 所有存储均使用 palloc() 分配（在前端代码中回退到 malloc）。
 *
 * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/lib/stringinfo.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef STRINGINFO_H
#define STRINGINFO_H

/*-------------------------
 * StringInfoData 保存有关可扩展字符串的信息。
 *		data	是字符串的当前缓冲区（使用 palloc 分配）。
 *		len		是当前字符串长度。可以保证在 data[len] 处有一个终止的 '\0'，尽管在字符串包含二进制数据而不是文本时，这并不是很有用。
 *		maxlen	是 'data' 的分配字节大小，即我们目前可以在 'data' 中存储的最大字符串大小（包括终止的 '\0' 字符），而无需重新分配更多空间。我们必须始终有 maxlen > len。
 *		cursor	由 makeStringInfo 或 initStringInfo 初始化为零，但在 stringinfo.c 例程中不会被其他方式修改。一些例程使用它扫描一个 StringInfo。
 *-------------------------
 */
typedef struct StringInfoData
{
	char	   *data;
	int			len;
	int			maxlen;
	int			cursor;
} StringInfoData;

typedef StringInfoData *StringInfo;


/*------------------------
 * 创建 StringInfo 对象有两种初始方法：
 *
 * StringInfo stringptr = makeStringInfo();
 *		既分配了 StringInfoData，又分配了数据缓冲区。
 *
 * StringInfoData string;
 * initStringInfo(&string);
 *		数据缓冲区被 palloc'ed 但 StringInfoData 只是局部的。
 *		这是创建仅在当前例程存在的 StringInfo 对象的最简单方法。
 *
 * 要销毁一个 StringInfo，首先使用 pfree() 释放数据缓冲区，然后如果 StringInfoData 是 palloc'ed，则再使用 pfree() 释放它。
 * 这没有特殊支持。
 *
 * 注意：一些例程使用 StringInfo 构建一个字符串，然后释放 StringInfoData，但将数据字符串本身返回给调用者。此时，数据字符串看起来像一个普通的 palloc'ed 字符串。
 *-------------------------
 */

/*------------------------
 * makeStringInfo
 * 创建一个空的 'StringInfoData' 并返回其指针。
 */
extern StringInfo makeStringInfo(void);

/*------------------------
 * initStringInfo
 * 初始化一个 StringInfoData 结构（具有先前未定义的内容）以描述一个空字符串。
 */
extern void initStringInfo(StringInfo str);

/*------------------------
 * resetStringInfo
 * 清除 StringInfo 的当前内容（如果有的话）。StringInfo 仍然是有效的。
 */
extern void resetStringInfo(StringInfo str);

/*------------------------
 * appendStringInfo
 * 在 fmt（一个 sprintf 风格的格式字符串）的控制下格式化文本数据，并将其附加到 str 中已有的内容。如果需要，向 str 分配更多空间。这有点像 sprintf 和 strcat 的结合。
 */
extern void appendStringInfo(StringInfo str, const char *fmt,...) pg_attribute_printf(2, 3);

/*------------------------
 * appendStringInfoVA
 * 尝试在 fmt（一个 sprintf 风格的格式字符串）的控制下格式化文本数据，并将其附加到 str 中已有的内容。如果成功返回零；如果不成功（因为空间不足），则返回所需空间的估计值，而不修改 str。通常调用者应该在再次尝试之前将返回值传递给 enlargeStringInfo()；有关标准使用模式，请参见 appendStringInfo。
 */
extern int	appendStringInfoVA(StringInfo str, const char *fmt, va_list args) pg_attribute_printf(2, 0);

/*------------------------
 * appendStringInfoString
 * 将一个以 null 结尾的字符串附加到 str 上。
 * 像 appendStringInfo(str, "%s", s) 但更快。
 */
extern void appendStringInfoString(StringInfo str, const char *s);

/*------------------------
 * appendStringInfoChar
 * 将一个字节附加到 str 上。
 * 像 appendStringInfo(str, "%c", ch) 但更快。
 */
extern void appendStringInfoChar(StringInfo str, char ch);

/*------------------------
 * appendStringInfoCharMacro
 * 如上，但这是一个宏，以便在重要的地方实现更高的速度。
 * 注意：str 参数将被多次评估。
 */
#define appendStringInfoCharMacro(str,ch) \
	(((str)->len + 1 >= (str)->maxlen) ? \
	 appendStringInfoChar(str, ch) : \
	 (void)((str)->data[(str)->len] = (ch), (str)->data[++(str)->len] = '\0'))

/*------------------------
 * appendStringInfoSpaces
 * 将给定数量的空格附加到 str 上。
 */
extern void appendStringInfoSpaces(StringInfo str, int count);

/*------------------------
 * appendBinaryStringInfo
 * 将任意二进制数据附加到 StringInfo，如果需要则分配更多空间。
 */
extern void appendBinaryStringInfo(StringInfo str,
								   const char *data, int datalen);

/*------------------------
 * appendBinaryStringInfoNT
 * 将任意二进制数据附加到 StringInfo，如果需要则分配更多空间。不会确保存在尾随的 null 字节。
 */
extern void appendBinaryStringInfoNT(StringInfo str,
									 const char *data, int datalen);

/*------------------------
 * enlargeStringInfo
 * 确保 StringInfo 的缓冲区至少可以容纳 'needed' 字节。
 */
extern void enlargeStringInfo(StringInfo str, int needed);

#endif							/* STRINGINFO_H */
